package com.gitee.wsl.api

import com.gitee.wsl.prop.PropContainerImpl

/**
 * 调用freeze函数之后对象成为不可变对象。一旦进入不可变状态就不可能再被修改
 */
interface IFreezable {

    var isFrozen:Boolean

    /**
     * 标记对象被冻结
     *
     * @param cascade 是否递归冻结子对象
     */
    fun freeze(cascade: Boolean) {
        isFrozen = cascade
    }

    companion object{

        fun checkNotFrozen(obj: IFreezable) {
            if (obj.isFrozen) throw Exception("ERR_CHECK_OBJ_IS_FROZEN")//.param(ARG_OBJ, obj)
        }

        fun <T> deepFreeze(o: T): T? {
            return _deepFreeze(o) as T?
        }

        private fun _deepFreeze(o: Any?): Any? {
            if (o == null) return null

            when (o) {
                is IFreezable -> {
                    o.freeze(true)
                    return o
                }

                is List<*> -> {
                    return freezeList(o.toMutableList() , true)
                } /*else if (o is SortedMap) {
                        return freezeSortedMap<Any, Any>(o as java.util.SortedMap?, true)
                    }*/
                is Map<*, *> -> {
                    return freezeMap(o.toMutableMap() , true)
                } /*else if (o is SortedSet) {
                        return freezeSortedSet<Any>(o as java.util.SortedSet?, true)
                    }*/
                is Set<*> -> {
                    return freezeSet(o, true)
                }
                else -> {
                    return o
                }
            }
        }

        fun freezeObj(obj: IFreezable, cascade: Boolean) {
            obj.freeze(cascade)
        }

        fun <T : IFreezable?> freezeItems(items: Collection<T>, cascade: Boolean) {
            for (item in items) {
                item?.freeze(cascade)
            }
        }

        fun deepFreezeObjects(items: Collection<*>) {
            for (item in items) {
                _deepFreeze(item)
            }
        }

        fun <T> freezeList(list: MutableList<T>, cascade: Boolean): List<T> {
            if (list.isEmpty()) return list
            if (cascade) {
                _deepFreezeList(list)
            }
            return list
        }

        fun <T> freezeSet(set: Set<T>, cascade: Boolean): Set<T> {
            if (set.isEmpty()) return set
            if (cascade) _deepFreezeItems(set)
            return set
        }

       /* fun <T> freezeSortedSet(
            set: java.util.SortedSet<T>?,
            cascade: Boolean,
        ): java.util.SortedSet<T>? {
            if (set == null || set === CloneHelper.EMPTY_SET) return set
            if (cascade) _deepFreezeItems(set)
            return java.util.Collections.unmodifiableSortedSet<T>(set)
        }*/

        fun <K, V> freezeMap(map: MutableMap<K, V?>, cascade: Boolean): Map<K, V?> {
            if (map.isEmpty()) return map
            if (cascade) _deepFreezeMap(map)
            return map
        }

        /*fun <K, V> freezeSortedMap(
            map: java.util.SortedMap<K, V>?,
            cascade: Boolean,
        ): java.util.SortedMap<K, V>? {
            if (map == null || map === CloneHelper.EMPTY_MAP) return map
            if (cascade) _deepFreezeMap(map)
            return java.util.Collections.unmodifiableSortedMap<K, V>(map)
        }*/

        private fun <T> _deepFreezeList(items: MutableList<T>) {
            var i = 0
            val n = items.size
            while (i < n) {
                val item = items[i]
                val o = _deepFreeze(item)
                if (item != o) {
                    items[i] = o as T
                }
                i++
            }
        }

        private fun <T> _deepFreezeItems(items: Collection<T>) {
            for (item in items) {
                _deepFreeze(item)
            }
        }

        private fun <K, V> _deepFreezeMap(map: MutableMap<K, V?>) {
            for (entry in map.entries) {
                val value = entry.value
                val o = _deepFreeze(value)
                if (o != value) entry.setValue(o as V?)
            }
        }

    }
}


open class AbstractFreezable: PropContainerImpl(),IFreezable{

    override var isFrozen:Boolean = false

    override fun freeze(cascade: Boolean) {
        isFrozen = cascade
    }

    fun checkAllowChange(){}

}

